package com.bookocean.application.service;

import com.bookocean.controller.dto.RewardDto;
import com.bookocean.infrastructure.persistence.mapper.RewardDefinitionMapper;
import com.bookocean.infrastructure.persistence.mapper.UserPointsMapper;
import com.bookocean.infrastructure.persistence.po.RewardDefinitionPO;
import com.bookocean.infrastructure.persistence.po.UserPointsPO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 奖励应用服务
 * 
 * @author BookOcean
 * @since 2024-01-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RewardApplicationService {

    private final RewardDefinitionMapper rewardDefinitionMapper;
    private final UserPointsMapper userPointsMapper;

    /**
     * 获取所有可用奖励
     * 
     * @return 奖励列表
     */
    public List<RewardDto> getAllRewards() {
        log.info("获取所有可用奖励");
        
        List<RewardDefinitionPO> rewardDefinitions = rewardDefinitionMapper.selectActiveRewards();
        return convertToRewardDtos(rewardDefinitions, null);
    }

    /**
     * 根据类型获取奖励
     * 
     * @param type 奖励类型
     * @return 奖励列表
     */
    public List<RewardDto> getRewardsByType(String type) {
        log.info("根据类型获取奖励，type: {}", type);
        
        List<RewardDefinitionPO> rewardDefinitions = rewardDefinitionMapper.selectRewardsByType(type);
        return convertToRewardDtos(rewardDefinitions, null);
    }

    /**
     * 根据积分范围获取奖励
     * 
     * @param minPoints 最小积分
     * @param maxPoints 最大积分
     * @return 奖励列表
     */
    public List<RewardDto> getRewardsByPointsRange(Integer minPoints, Integer maxPoints) {
        log.info("根据积分范围获取奖励，minPoints: {}, maxPoints: {}", minPoints, maxPoints);
        
        List<RewardDefinitionPO> rewardDefinitions = rewardDefinitionMapper.selectRewardsByPointsRange(minPoints, maxPoints);
        return convertToRewardDtos(rewardDefinitions, null);
    }

    /**
     * 获取用户可兑换的奖励列表
     * 
     * @param userId 用户ID
     * @return 奖励列表（包含用户当前积分和可兑换状态）
     */
    public List<RewardDto> getUserAvailableRewards(Long userId) {
        log.info("获取用户可兑换的奖励列表，userId: {}", userId);
        
        // 获取所有可用奖励
        List<RewardDefinitionPO> rewardDefinitions = rewardDefinitionMapper.selectActiveRewards();
        
        // 获取用户当前积分
        UserPointsPO userPoints = userPointsMapper.selectUserPoints(userId);
        Integer userCurrentPoints = 0;
        if (userPoints != null) {
            userCurrentPoints = userPoints.getAvailablePoints();
        }
        
        return convertToRewardDtos(rewardDefinitions, userCurrentPoints);
    }

    /**
     * 获取奖励详情
     * 
     * @param rewardId 奖励ID
     * @param userId 用户ID（可选，用于计算是否可兑换）
     * @return 奖励详情
     */
    public RewardDto getRewardDetail(Long rewardId, Long userId) {
        log.info("获取奖励详情，rewardId: {}, userId: {}", rewardId, userId);
        
        RewardDefinitionPO rewardDefinition = rewardDefinitionMapper.selectById(rewardId);
        if (rewardDefinition == null) {
            throw new RuntimeException("奖励不存在");
        }
        
        Integer userCurrentPoints = null;
        if (userId != null) {
            UserPointsPO userPoints = userPointsMapper.selectUserPoints(userId);
            if (userPoints != null) {
                userCurrentPoints = userPoints.getAvailablePoints();
            }
        }
        
        return convertToRewardDto(rewardDefinition, userCurrentPoints);
    }

    /**
     * 兑换奖励
     * 
     * @param userId 用户ID
     * @param rewardId 奖励ID
     * @return 是否成功
     */
    @Transactional
    public boolean redeemReward(Long userId, Long rewardId) {
        log.info("兑换奖励，userId: {}, rewardId: {}", userId, rewardId);
        
        // 1. 检查奖励是否存在且可用
        RewardDefinitionPO rewardDefinition = rewardDefinitionMapper.selectById(rewardId);
        if (rewardDefinition == null || !rewardDefinition.getIsActive()) {
            throw new RuntimeException("奖励不存在或已禁用");
        }
        
        // 2. 检查用户积分是否足够
        UserPointsPO userPoints = userPointsMapper.selectUserPoints(userId);
        if (userPoints == null || userPoints.getAvailablePoints() < rewardDefinition.getPointsCost()) {
            throw new RuntimeException("积分不足，无法兑换");
        }
        
        // 3. 扣除用户积分
        int result = userPointsMapper.consumeUserPoints(userId, rewardDefinition.getPointsCost());
        if (result <= 0) {
            throw new RuntimeException("积分扣除失败");
        }
        
        // 4. 这里可以添加具体的奖励发放逻辑
        // 例如：发放优惠券、增加权限等
        log.info("奖励兑换成功，userId: {}, rewardId: {}, pointsCost: {}", 
                userId, rewardId, rewardDefinition.getPointsCost());
        
        return true;
    }

    /**
     * 为用户增加积分
     * 
     * @param userId 用户ID
     * @param points 积分数量
     * @param reason 积分来源原因
     * @return 是否成功
     */
    @Transactional
    public boolean addUserPoints(Long userId, Integer points, String reason) {
        log.info("为用户增加积分，userId: {}, points: {}, reason: {}", userId, points, reason);
        
        if (points <= 0) {
            throw new RuntimeException("积分数量必须大于0");
        }
        
        // 检查用户是否有积分记录
        UserPointsPO userPoints = userPointsMapper.selectUserPoints(userId);
        if (userPoints == null) {
            // 创建新的积分记录
            userPoints = new UserPointsPO();
            userPoints.setUserId(userId);
            userPoints.setTotalPoints(points);
            userPoints.setAvailablePoints(points);
            userPoints.setCreatedAt(LocalDateTime.now());
            userPoints.setUpdatedAt(LocalDateTime.now());
            userPointsMapper.insert(userPoints);
        } else {
            // 更新现有积分记录
            int result = userPointsMapper.updateUserPoints(userId, points);
            if (result <= 0) {
                throw new RuntimeException("积分更新失败");
            }
        }
        
        log.info("积分增加成功，userId: {}, points: {}, reason: {}", userId, points, reason);
        return true;
    }

    /**
     * 获取用户积分信息
     * 
     * @param userId 用户ID
     * @return 用户积分信息
     */
    public UserPointsPO getUserPoints(Long userId) {
        log.info("获取用户积分信息，userId: {}", userId);
        
        return userPointsMapper.selectUserPoints(userId);
    }

    /**
     * 转换奖励定义PO为DTO列表
     * 
     * @param rewardDefinitions 奖励定义列表
     * @param userCurrentPoints 用户当前积分（可选）
     * @return 奖励DTO列表
     */
    private List<RewardDto> convertToRewardDtos(List<RewardDefinitionPO> rewardDefinitions, Integer userCurrentPoints) {
        return rewardDefinitions.stream()
                .map(reward -> convertToRewardDto(reward, userCurrentPoints))
                .collect(Collectors.toList());
    }

    /**
     * 转换奖励定义PO为DTO
     * 
     * @param rewardDefinition 奖励定义
     * @param userCurrentPoints 用户当前积分（可选）
     * @return 奖励DTO
     */
    private RewardDto convertToRewardDto(RewardDefinitionPO rewardDefinition, Integer userCurrentPoints) {
        RewardDto rewardDto = new RewardDto();
        rewardDto.setRewardId(rewardDefinition.getRewardId());
        rewardDto.setName(rewardDefinition.getName());
        rewardDto.setDescription(rewardDefinition.getDescription());
        rewardDto.setType(rewardDefinition.getType());
        rewardDto.setPointsCost(rewardDefinition.getPointsCost());
        rewardDto.setIsActive(rewardDefinition.getIsActive());
        rewardDto.setCreatedAt(rewardDefinition.getCreatedAt());
        
        if (userCurrentPoints != null) {
            rewardDto.setUserCurrentPoints(userCurrentPoints);
            rewardDto.setCanRedeem(userCurrentPoints >= rewardDefinition.getPointsCost());
        }
        
        return rewardDto;
    }
}
